package com.samphanie.auiu.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.samphanie.auiu.auth.feign.IThirdPartyService;
import com.samphanie.auiu.auth.service.IRoleService;
import com.samphanie.auiu.auth.service.IUserCacheService;
import com.samphanie.auiu.auth.service.IUserRoleService;
import com.samphanie.auiu.auth.service.IUserService;
import com.samphanie.auiu.auth.utils.TotpUtil;
import com.samphanie.auiu.common.constants.AuiuConstants;
import com.samphanie.auiu.common.exception.ApiException;
import com.samphanie.auiu.mbg.mapper.UserMapper;
import com.samphanie.auiu.mbg.model.SysRole;
import com.samphanie.auiu.mbg.model.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;
import java.util.Set;

/**
 * @author Dries
 * @email 1451691457@qq.com
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final IRoleService roleService;
    private final PasswordEncoder passwordEncoder;
    private final IUserRoleService userRoleService;

    private final TotpUtil totpUtil;
    private final IUserCacheService userCacheService;
    private final IThirdPartyService thirdPartyService;

    /**
     * 注册一个新用户
     *
     * @param user 用户实体
     * @return 保存后的对象
     */
    @Override
    public User register(User user) {
        return roleService.findOptionalByRoleName(AuiuConstants.ROLE_USER)
                .map(role -> {
                    val userToSave = user
                            .withRoles(Set.of(role))
                            .withPassword(passwordEncoder.encode(user.getPassword()))
                            .withMfaKey(totpUtil.encodeKeyToString());
                    return saveUser(userToSave);
                })
                .orElseThrow(() -> new ApiException("注册失败"));
    }


    @Override
    public boolean isUsernameExisted(String username) {
        return baseMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getUsername, username)) > 0;
    }

    @Override
    public boolean isEmailExisted(String email) {
        return baseMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getEmail, email)) > 0;
    }

    @Override
    public boolean isMobileExisted(String mobile) {
        return baseMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile)) > 0;
    }

    /**
     * 根据用户名查找用户
     *
     * @param username 用户
     * @return 可能为空的用户
     */
    @Override
    public Optional<User> findOptionalByUsername(String username) {

        return Optional.ofNullable(
                baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username))
        ).map(user -> {
            Set<SysRole> roleList = userRoleService.getRoleList(user.getId());
            user.setRoles(roleList);
            return user;
        });
    }

    /**
     * 根据手机号查找用户
     *
     * @param mobile 手机号
     * @return 可能为空的用户
     */
    @Override
    public Optional<User> findOptionalByMobile(String mobile) {
        return Optional.ofNullable(
                baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile))
        );
    }

    /**
     * 根据邮箱查找用户
     *
     * @param email 邮箱
     * @return 可能为空的用户
     */
    @Override
    public Optional<User> findOptionalByEmail(String email) {
        return Optional.ofNullable(
                baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email))
        );
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public User saveUser(User user) {
        int result = baseMapper.insert(user);
        return result > 0 ? user : null;
    }

    @Override
    public Optional<User> findOptionalByUsernameAndPassword(String username, String password) {
        return findOptionalByUsername(username).filter(user -> passwordEncoder.matches(password, user.getPassword()));
    }

    @Override
    public void validateUserUniqueFields(String username, String email, String mobile) {
        if (isUsernameExisted(username)) {
            throw new ApiException("用户名已存在");
        }
        if (isEmailExisted(email)) {
            throw new ApiException("电子邮件已存在");
        }
        if (isMobileExisted(mobile)) {
            throw new ApiException("手机号已存在");
        }
    }

    @Override
    public Optional<String> createTotp(User user) {
        return totpUtil.createTotp(user.getMfaKey());
    }
}
